package thread;

/**
 * 没有因为多线程带来bug，认为线程安全
 * 1.共享数据
 * 2.原子性：要么执行成功，要么失败，不会执行一般，不存在中间态
 * 写操作很多都是非原子性（先读，再去写）
 * 3.内存可见性
 * 先从主内存中，把数据读到现成的工作内存中，然后对数据进行修改，再把数据从工作内存中刷回到主内存中
 * 4.指令重排序：遵循happen-before
 * 不能改变程序的执行结果
 * 单线程简单可以保证
 * 多线程比较复杂，不太能保证
 * 线程安全三大特性：原子性，内存可见性，指令重排序
 * ///////////////////////////////////////////////
 * synchronized
 * 1.修饰普通方法：等同于synchronized(this){}
 * 该实例，该对象this
 * 2.修饰静态方法：等同于synchronized(类名.class){}
 * 锁对象：是类对象
 * 3.修饰代码块:明确写出来，加的锁对象是谁synchronized()
 * 指令重排序：synchronized只有一定的约束，并不能完全禁止指令重排序
 *    所以有时候单靠synchronized并不能完全解决线程安全的问题，还需要搭配一些其他操作
 * ///////////////////////////////////////////
 * volatile：易变的，强制执行顺序
 * 被volatile修饰的变量是易变的
 * 申请一块内存空间，初始化，把引向指向内存空间
 * volatile保证了内存可见性
 * 1.不能保证原子性（也不会线程阻塞，因为没有锁）
 * 2.可以保证内存的可见性
 *   1）读数据，强制从主内存读数据
 *   2）写数据，强制把工作的数据写到主内存
 * 3.禁止指令重排序
 * ////////////////////////////////
 * synchronized和volatile的区别
 * 1.synchronized通过加锁解锁的方式把一堆代码绑在一起，来保证原子性
 *               通过加锁解锁的方式来保证内存可见性
 *               对指令重排序有一定的约束
 *   volatile不能保证原子性
 *           保证内存可见性
 *           禁止指令重排序
 * wait & notify/notifyALL 通知等待机制
 * wait等待的是一个对象A，A.wait只能被A.notify唤醒
 * notify 唤醒一个          B.notify就不能唤醒
 * notifyALL全部唤醒
 */
public class Demo10 {
}
